//mpic++ mainAlex.cpp -o mainAlex -g
//mpirun -np 4 mainAlex
//mpirun -np 4 valgrind ./mainAlex

#include <mpi.h>
#include <iostream>
#include <cstdlib>
#include <string>   // pour std::string
#include <fstream>  // pour les fichiers
#define ECART 0.0001
#define ECOULEMENT_INCONNU 10
using namespace std;

int sommeTableau(int * tableau , int taille){
    int res=0;
    for(int i=0; i<taille;i++){
        res+=tableau[i];
    }
    return res;
}

void afficheRESCASE(int * tab,int taille){
    for(int i = 0 ; i < taille; i++){
        cout<<tab[i]<<" "<<endl;
    }
    cout<<endl;
}

void rassemblerResultat(int ** resPhaseIII, int pid,int nbprocs,int nrows, int ncols){
    int * resultatCase;
    resultatCase = new int[nbprocs];

    //for(int
    //recuperer le tableau resultat
    for(int lig=0 ; lig<nrows ; lig++){
        for(int col = 0; col< ncols; col++){
            MPI_Gather(&resPhaseIII[lig][col],1,MPI_INT,resultatCase,1,MPI_INT,0,MPI_COMM_WORLD);
            //Apres le gather, dans le tableau resultatCase, on a le resultat de tous les processeurs
            //On fais une somme pour récupérer la valeur qui a été trouvée par un des processeur
            if(pid == 0){
                //afficheRESCASE(resultatCase,nbprocs);
                resPhaseIII[lig][col]=sommeTableau(resultatCase,nbprocs);
                //cout<<"un cas est modifée "<< resPhaseIII[lig][col]<<endl;
            }
        }

    }
}


bool isVoisinCoulant(int ** lesDirs,int nrows, int ncols, int ligdest, int coldest, int ligsource, int colsource){
    if(ligdest >= 0 &&ligdest < nrows && coldest >=0 && coldest<ncols){
        int value = lesDirs[ligdest][coldest];
      //  cout<<"value ecoulement : "<<value<<endl;
      //  cout<<"ligSource : "<<ligsource<<endl;
     //   cout<<"colsource : "<<colsource<<endl;
       // cout<<"ligDest : "<<ligdest<<endl;
      //  cout<<"colDest : "<<coldest<<endl;
        switch(value){
        case 0 :  break;
        case 1 :
            if(ligdest -1 == ligsource  && coldest -1 == colsource){
                return true;
            }
            break;
        case 2 :
            if(ligdest -1 == ligsource  && coldest == colsource){
                return true;
            }
            break;
        case 3 :
            if(ligdest -1 == ligsource  && coldest +1 == colsource){
                return true;
            }
            break;
        case 4 :
            if(ligdest  == ligsource  && coldest +1 == colsource){
                return true;
            }
            break;
        case 5 :
            if(ligdest +1 == ligsource  && coldest +1 == colsource){
                return true;
            }
            break;
        case 6 :
            if(ligdest +1 == ligsource  && coldest  == colsource){
                return true;
            }
            break;
        case 7 :
            if(ligdest +1 == ligsource  && coldest -1 == colsource){
                return true;
            }
            break;
        case 8 :
            if(ligdest  == ligsource  && coldest -1 == colsource){
                return true;
            }
            break;
        default : 
	  break;
        }

    }
   // cout<<"Return false"<<endl;
    return false;
}




/**
 * Fonction qui va etre appelée initialement sur une cuvette,
 * puis récursivement sur chaque case qui constitue a partir du puits, vers les sources
 * @param ecoulementsLocaux : les ecoulements vers les voisins
 * @param ecoulementsGlobaux : les ecoulements bout à bout, parametre mis a jour au fur et a mesure
 * @param ligneCourante : la ligne de la case a traiter
 * @param colCourante : la colonne de la case a traiter
 * @param ligneDepart : la ligne de la case qui a initialisé l'appel récursif
 * @param colDepart : la colonne de la case qui a initialisé l'appel récursif
 */
int trouverAccumulationRec(int ** lesDirs, int ** ecoulementsGlobaux,int nrows, int ncols, int ligneCourante, int colCourante){
    //cout<<"Debut de AccumulRec"<<endl;
    //Pour chaque voisin qui pointe vers moi
    //
    //cout<<"appel a AccumulRec sur la case qui contient"<<lesDirs[ligneCourante][colCourante]<<" "<<ecoulementsGlobaux[ligneCourante][colCourante]<<endl;
    int res=1;
    int rowVoisin;
    int colVoisin;
    /*
    for(int i=0; i<nrows; i++){
     for(int j=0; j<ncols; j++){
	cout<<ecoulementsGlobaux[ligneCourante][colCourante]<<" ";
      }
      cout<<endl;
    }
    cout<<"-----"<<endl;
    */
    //Haut gauche
   // cout<<"ligneCourante : "<<ligneCourante<<endl;
  //  cout<<"colCourante : "<<colCourante<<endl;
    rowVoisin=ligneCourante-1;
    colVoisin=colCourante-1;
    if(isVoisinCoulant(lesDirs,nrows,ncols,rowVoisin,colVoisin,ligneCourante,colCourante)){
   //     cout<<"Voisin 1"<<endl;
   //cout<<"mon voisin 1 s'ecoule vers moi et sa valeur est "<<ecoulementsGlobaux
        // ecoulementsGlobaux[ligneCourante][colCourante]++; //La valeur augmente a cause d'un voisin proche
        res+=trouverAccumulationRec(lesDirs,ecoulementsGlobaux,nrows,ncols,rowVoisin,colVoisin);
    }
    //Haut
    rowVoisin=ligneCourante-1;
    colVoisin=colCourante;
    if(isVoisinCoulant(lesDirs,nrows,ncols,rowVoisin,colVoisin,ligneCourante,colCourante)){
     //   cout<<"Voisin 2"<<endl;
        // ecoulementsGlobaux[ligneCourante][colCourante]++; //La valeur augmente a cause d'un voisin proche
        res+=trouverAccumulationRec(lesDirs,ecoulementsGlobaux,nrows,ncols,rowVoisin,colVoisin);
    }
    //Haut droit
    rowVoisin=ligneCourante-1;
    colVoisin=colCourante+1;
    if(isVoisinCoulant(lesDirs,nrows,ncols,rowVoisin,colVoisin,ligneCourante,colCourante)){
       // cout<<"Voisin 3"<<endl;
        // ecoulementsGlobaux[ligneCourante][colCourante]++; //La valeur augmente a cause d'un voisin proche
        res+=trouverAccumulationRec(lesDirs,ecoulementsGlobaux,nrows,ncols,rowVoisin,colVoisin);
    }

    //Gauche
    rowVoisin=ligneCourante;
    colVoisin=colCourante-1;
   // cout<<"rowVoisin "<<rowVoisin<<endl;
   // cout<<"colVoisin "<<colVoisin<<endl;
    if(isVoisinCoulant(lesDirs,nrows,ncols,rowVoisin,colVoisin,ligneCourante,colCourante)){
      //  cout<<"Voisin 4"<<endl;
        // ecoulementsGlobaux[ligneCourante][colCourante]++; //La valeur augmente a cause d'un voisin proche
        res+=trouverAccumulationRec(lesDirs,ecoulementsGlobaux,nrows,ncols,rowVoisin,colVoisin);
    }
    //Droit
    rowVoisin=ligneCourante;
    colVoisin=colCourante+1;
    if(isVoisinCoulant(lesDirs,nrows,ncols,rowVoisin,colVoisin,ligneCourante,colCourante)){
      //  cout<<"Voisin 5"<<endl;
        //ecoulementsGlobaux[ligneCourante][colCourante]++; //La valeur augmente a cause d'un voisin proche
        res+=trouverAccumulationRec(lesDirs,ecoulementsGlobaux,nrows,ncols,rowVoisin,colVoisin);
    }
    //Bas Gauche
    rowVoisin=ligneCourante+1;
    colVoisin=colCourante-1;
    if(isVoisinCoulant(lesDirs,nrows,ncols,rowVoisin,colVoisin,ligneCourante,colCourante)){
       // cout<<"Voisin 6"<<endl;
        // ecoulementsGlobaux[ligneCourante][colCourante]++; //La valeur augmente a cause d'un voisin proche
        res+=trouverAccumulationRec(lesDirs,ecoulementsGlobaux,nrows,ncols,rowVoisin,colVoisin);
    }
    //Bas
    rowVoisin=ligneCourante+1;
    colVoisin=colCourante;
    if(isVoisinCoulant(lesDirs,nrows,ncols,rowVoisin,colVoisin,ligneCourante,colCourante)){
       // cout<<"Voisin 7"<<endl;
        //ecoulementsGlobaux[ligneCourante][colCourante]++; //La valeur augmente a cause d'un voisin proche
        res+=trouverAccumulationRec(lesDirs,ecoulementsGlobaux,nrows,ncols,rowVoisin,colVoisin);
    }
    //Bas droit
    rowVoisin=ligneCourante+1;
    colVoisin=colCourante+1;
    if(isVoisinCoulant(lesDirs,nrows,ncols,rowVoisin,colVoisin,ligneCourante,colCourante)){
       // cout<<"Voisin 8"<<endl;
        //ecoulementsGlobaux[ligneCourante][colCourante]++; //La valeur augmente a cause d'un voisin proche
        res+=trouverAccumulationRec(lesDirs,ecoulementsGlobaux,nrows,ncols,rowVoisin,colVoisin);
    }
    ecoulementsGlobaux[ligneCourante][colCourante]+=res;
    return res;
}



void chargerPhIII(int ** & leMNT, int  & ncols,int & nrows,int & xllcorner, int & yllcorner, int & cellsize, float & NODATA_value){
    ifstream file("phaseII.txt", ios::in);
    string trash;

    if(file){
        cout<<"fichier phaseII.txt ouvert correctement"<<endl;
        file >> trash;
        file >> ncols;
        file >> trash;
        file >> nrows;
        file >> trash;
        file >> xllcorner;
        file >> trash;
        file >> yllcorner;
        file >> trash;
        file >> cellsize;
        file >> trash;
        file >> NODATA_value;
        leMNT =new int*[nrows]; // nb de ligne et donc taille d'une colonne
        for(int i= 0; i< nrows ; i++){
            leMNT[i] = new int[ncols]; // allocation d'une ligne
        }
        // on passe au remplissage du tableau
        for(int lig=0; lig<nrows ;lig++){
            for(int col= 0; col < ncols ; col++){
                file >> leMNT[lig][col];
                //cout<<leMNT[lig][col]<<" ";
                //attention les coordonnées sont inversées , en effet
                // de part la création, on est obligé de mettre
                // l'ordonnée(lig) en premier dans l'allocation
                // et l'abscisse en second
                // faire attention pour plus tard
            }
            //cout<<endl;
        }
    }
    else{
        cout<<"impossible d'ouvrir le fichier"<<endl;
    }
}

/**
 * Convertir une coordonnée (ligne,colonne) avec un direction en la coordonnée destination
 */
void modifCoord(int dir,int &col, int &lig){
    switch(dir){
    case 1 : col--;lig--;break;
    case 2 : lig--;break;
    case 3 : col++;lig--;break;
    case 4 : col++;break;
    case 5 : col++;lig++;break;
    case 6 : lig++;break;
    case 7 : col--;lig++;break;
    case 8 : col--;break;
    default: break;
    }
}

bool allZero(int * tab,int ncols){
    for(int i = 0 ; i < ncols; i++ ){
        if(tab[i] != 0){
            return false;
        }
    }
    return true;
}

void resetTab(int * tab,int value, int ncols){
    for(int i = 0 ; i< ncols; i++){
        tab[i] = value;
    }
}

int * initZero(int ncols){
    int  * res = new int [ncols];
    for(int i = 0 ; i < ncols ; i++){
        res[i]  = 0;
    }
    return res;
}


/**
 * 
 */
void ecoulement(int ** res, int ** lesDirs, int lig, int col, int nrows, int ncols,int val,int pid,int nbprocs, int * dessus, int * dessous){
    if(col >= 0 && col < ncols){
        if(lig >= 0 && lig < nrows){
            //col et lig valide
            if(res[lig][col] == 0){
                //premiere fois qu'on passe dnas la case
                res[lig][col]++;
                res[lig][col]+=val;
                val = res[lig][col];
            }
            else{
                    //si c'ets la premiere fois que l'on recoit du precedent
                    //on ajoute ça valeur a nous
                    res[lig][col]+=val;
            }
            // affiche(res,ncols,nrows);
            // cout<<endl;cout<<endl;cout<<endl;
            int dir = lesDirs[lig][col];
            switch(dir){
            case 0 : /* do nothing */ break;
            case 1 :
                //hautgauche
                ecoulement(res,lesDirs,lig-1,col-1,nrows,ncols,val,pid,nbprocs,dessus,dessous);
                break;
            case 2 :
                //haut
                ecoulement(res,lesDirs,lig-1,col,nrows,ncols,val,pid,nbprocs,dessus,dessous);
                break;
            case 3 :
                //hautdroit
                ecoulement(res,lesDirs,lig-1,col+1,nrows,ncols,val,pid,nbprocs,dessus,dessous);
                break;
            case 4 :
                //droit
                ecoulement(res,lesDirs,lig,col+1,nrows,ncols,val,pid,nbprocs,dessus,dessous);
                break;
            case 5 :
                //basdroit
                ecoulement(res,lesDirs,lig+1,col+1,nrows,ncols,val,pid,nbprocs,dessus,dessous);
                break;
            case 6 :
                //bas
                ecoulement(res,lesDirs,lig+1,col,nrows,ncols,val,pid,nbprocs,dessus,dessous);
                break;
            case 7 :
                //basgauche
                ecoulement(res,lesDirs,lig+1,col-1,nrows,ncols,val,pid,nbprocs,dessus,dessous);
                break;
            case 8 :
                //gauche
                ecoulement(res,lesDirs,lig,col-1,nrows,ncols,val,pid,nbprocs,dessus,dessous);
                break;
            }
        }
        else{
            //ligne invalide, soit on ecrit dessus ou dessous depend du pid
            if(pid==0){
                if(lig == nrows){
                    //on sort du tab par le dessous donc on ecrit dnas dessous
                        dessous[col]+=val;
                }
            }
            else{
                if(pid == nbprocs-1){
                    if(lig == -1){
                        //on sort du tab par le dessus donc on ecrit dnas dessus
                            //premiere fois qu'on passe dnas la case
                            dessus[col]+=val;
                    }
                }
                else{
                    if(lig == -1){
                        //on sort du tab par le dessus donc on ecrit dnas dessus
                            dessus[col]+=val;
                    }
                    else{
                        if(lig == nrows){
                            //on sort du tab par le dessous donc on ecrit dnas dessous
                            dessous[col]+=val;
                        }
                    }
                }
            }
        }
    }
    else{
        //do nothing
    }
}

/**
 * 
 */
int ** initResPhIII(int ncols, int nrows, int default_value){
    int ** res = new int*[nrows];
    for(int i = 0 ; i< nrows;i++){
        res[i] = new int[ncols];
    }

    //init a 0;
    for(int lig= 0; lig < nrows; lig++){
        for (int col =0; col<ncols; col++) {
            res[lig][col] = default_value;
        }
    }
    return res;
}

/**
 * Trouver la direction de l'ecoulement d'une case donnée, grâce aux altitudes
 * @param tab : le tableau des altitudes
 * @param tranche : le nombre de lignes du tableau
 * @param l : ligne de la case
 * @param c : colonne de la case
 */
int retourneDirEcoul(float** tab, int tranche, int ncols, int l, int c,float nodata){
    int res= 0; //doit retourner un chiffre entre 0 et 9, 0 c'est la case elle meme, 2 le haut,etc..
    float value = tab[l][c];
    if(tab[l][c]==nodata){
      return ECOULEMENT_INCONNU;
    }
    //bas droit 5
    if(l< tranche-1 && c< ncols-1){
        if(tab[l+1][c+1]<= value){
            value = tab[l+1][c+1];
            res=  5;
        }
    }

    //bas 6
    if(l<tranche-1){
        if(tab[l+1][c]<= value){
            value  = tab[l+1][c];
            res=  6;
        }
    }

    //bas gauche 7
    if(l< tranche-1 && c > 0){
        if(tab[l+1][c-1]<= value){
            value = tab[l+1][c-1];
            res = 7;
        }
    }

    //droit 4
    if(c < ncols -1){
        if(tab[l][c+1] <= value){
            value = tab[l][c+1];
            res= 4;
        }
    }


    //centre
    if(tab[l][c] <= value){
        value= tab[l][c];
        res = 0;
    }

    //gauche 8
    if(c>0){
        if(tab[l][c-1] <= value){
            value = tab[l][c-1];
            res= 8;
        }
    }

    //hautdroit 3
    if( l > 0 && c< ncols-1){
        if( tab[l-1][c+1] <= value){
            value = tab[l-1][c+1];
            res = 3 ;
        }
    }

    //haut 2
    if(l > 0){
        if(tab[l-1][c] <=  value){
            value = tab[l-1][c];
            res = 2;
        }
    }

    //haut gauche 1
    if( l>0 && c>0){
        //on peux vérif haut gauche
        if( tab[l-1][c-1] <= value){
            value = tab[l-1][c-1];
            res = 1;
        }
    }


    return res;
}

/**
 * Trouver la valeur a appliquer pour remplir le MNT lors de l'etape 1.
 * Il faut trouver le point d'altitude maximum et appliquer son altitude + une constante a tous les points du MNT
 */
float valRemplissage(float ** MNT, int ncols, int nrows, float ecart){
    float res = 0;
    for(int l = 0 ; l < nrows ; l++){
        for(int c =0 ;  c< ncols ; c++){
            if(MNT[l][c] > res){
                res = MNT[l][c];
            }
        }
    }
    return res + ecart;
    //retourne la valuer max du MNT + un écart choisi
}

/**
 * Fonction pour chacun des 8 voisins d'une certaine case,
 * qui va mettre a jour l'altitude dans W de la case concernée si nécessaire
 * @param W : la matrice innondée a mettre a jour
 * @param Z : la matrice des altitudes
 * @param row : la ligne de la case
 * @param col : la colonne de la case
 * @return 1 si il y a eu un changement, 0 si pas de changement
 * (on utilise un entier a la place d'un boolean car MPI ne définit pas un type booleen, et on a besoin de faire un gather sur le resultat de cette fonction) 
 */
int modif8Voisins(float ** W ,float ** Z, int row, int col, float nodata){
    int res =0;
    int lnew; //ordonnee de la cellule voisine visitee
    int cnew; //abscisse de la cellule voisine visitée
    //la voisine visitee sera appellee n
    //c'est parti pour les huits cas
    //cas bas droite
    //gestion du cas ou la cellule contient nodata
    if(Z[row][col]==nodata){
	//Si la meme case dans W ne contenait pas la valeur nodata
	if(W[row][col]!=nodata){
	  //alors je place nodata dans W
	  W[row][col]=nodata;
	  return 1;
	}
	else return 0;
    }
    lnew = row+1;
    cnew = col+1;
    if(Z[row][col] >= (W[lnew][cnew] + ECART)){
        //si Z(c) <= W(n)+epsilon(c,n)
        W[row][col] = Z[row][col]; //W(c) =Z(c)
        res= 1;
    }
    else{
        if(W[row][col] > (W[lnew][cnew] + ECART)){
            //sinon si W(c) >W(n)+ epsilon(c,n)
            W[row][col] = W[lnew][cnew] + ECART; // W(c) =W(n) + epsilon
            res=1;
        }
    }

    //cas bas
    lnew= row+1;
    cnew = col;
    if(Z[row][col] >= (W[lnew][cnew] + ECART)){
        //si Z(c) <= W(n)+epsilon(c,n)
        W[row][col] = Z[row][col]; //W(c) =Z(c)
        res=1;
    }
    else{
        if(W[row][col] > (W[lnew][cnew] + ECART)){
            //sinon si W(c) >W(n)+ epsilon(c,n)
            W[row][col] = W[lnew][cnew] + ECART; // W(c) =W(n) + epsilon
            res=1;
        }
    }

    //cas bas gauche
    lnew = row+1;
    cnew= col-1;
    if(Z[row][col] >= (W[lnew][cnew] + ECART)){
        //si Z(c) <= W(n)+epsilon(c,n)
        W[row][col] = Z[row][col]; //W(c) =Z(c)
        res=1;
    }
    else{
        if(W[row][col] > (W[lnew][cnew] + ECART)){
            //sinon si W(c) >W(n)+ epsilon(c,n)
            W[row][col] = W[lnew][cnew] + ECART; // W(c) =W(n) + epsilon
            res=1;
        }
    }

    //cas droite
    lnew= row;
    cnew= col+1;
    if(Z[row][col] >= (W[lnew][cnew] + ECART)){
        //si Z(c) <= W(n)+epsilon(c,n)
        W[row][col] = Z[row][col]; //W(c) =Z(c)
        res= 1;
    }
    else{
        if(W[row][col] > (W[lnew][cnew] + ECART)){
            //sinon si W(c) >W(n)+ epsilon(c,n)
            W[row][col] = W[lnew][cnew] + ECART; // W(c) =W(n) + epsilon
            res=1;
        }
    }

    //cas gauche
    lnew= row;
    cnew= col-1;
    if(Z[row][col] >= (W[lnew][cnew] + ECART)){
        //si Z(c) <= W(n)+epsilon(c,n)
        W[row][col] = Z[row][col]; //W(c) =Z(c)
        res= 1;
    }
    else{
        if(W[row][col] > (W[lnew][cnew] + ECART)){
            //sinon si W(c) >W(n)+ epsilon(c,n)
            W[row][col] = W[lnew][cnew] + ECART; // W(c) =W(n) + epsilon
            res=1;
        }
    }

    //cas haut droite
    lnew = row-1;
    cnew = col+1;
    if(Z[row][col] >= (W[lnew][cnew] + ECART)){
        //si Z(c) <= W(n)+epsilon(c,n)
        W[row][col] = Z[row][col]; //W(c) =Z(c)
        res= 1;
    }
    else{
        if(W[row][col] > (W[lnew][cnew] + ECART)){
            //sinon si W(c) >W(n)+ epsilon(c,n)
            W[row][col] = W[lnew][cnew] + ECART; // W(c) =W(n) + epsilon
            res=1;
        }
    }

    //cas haut
    lnew = row-1;
    cnew=col;
    if(Z[row][col] >= (W[lnew][cnew] + ECART)){
        //si Z(c) <= W(n)+epsilon(c,n)
        W[row][col] = Z[row][col]; //W(c) =Z(c)
        res= 1;
    }
    else{
        if(W[row][col] > (W[lnew][cnew] + ECART)){
            //sinon si W(c) >W(n)+ epsilon(c,n)
            W[row][col] = W[lnew][cnew] + ECART; // W(c) =W(n) + epsilon
            res=1;
        }
    }

    // cas haut gauche
    lnew = row-1;
    cnew = col-1;
    if(Z[row][col] >= (W[lnew][cnew] + ECART)){
        //si Z(c) <= W(n)+epsilon(c,n)
        W[row][col] = Z[row][col]; //W(c) =Z(c)
        res= 1;
    }
    else{
        if(W[row][col] > (W[lnew][cnew] + ECART)){
            //sinon si W(c) >W(n)+ epsilon(c,n)
            W[row][col] = W[lnew][cnew] + ECART; // W(c) =W(n) + epsilon
            res= 1;
        }
    }

    return res;
}

/**
 * Pour chaque processeur, allouer la matrice d'altitudes et la matrice innondée,
 * et rassembler les morceaux : 
 * - le premier processeur ne connait pas sa derniere et doit la demander au processeur suivant
 * - le dernier processeur ne connait pas sa premier ligne et doit la demander au processeur précédent
 * - un processeur quelconque ne connait ni sa 1ere ligne ni sa dernière ligne, et en fait la demande aux processeurs précédent / suivant 
 * @param donnees : la partie des altitudes connue dès le départ par ce processeur
 * @param Z : le tableau complet des altitudes pour ce processeur
 * @param W : la matrice innondée que l'on doit calculer
 * @param dessus : la premiere ligne de la matrice des altitudes qui doit etre ajoutée a "donnees"
 * @param dessous : la derniere ligne de la matrice des altitudes qui doit etre ajoutée a "donnees"
 * 
 * Pour gérer les envois et récépetion multiples des différents processeurs, on prend la convention suivante :
 * les processeurs de pid pair envoie puis recoivent
 * les processeurs de pid impair recoivent puis envoient
 */
void initTabPhaseI(float** donnees,float ** &Z, float ** &W,
                   float * dessus, float * dessous,
                   int trancheProcZero, int tranche, int ncols,
                   int pid, int nbprocs,MPI_Datatype my_line){
    if(pid==0){
        //on dois considérer tranche proc 0 + ligne du dessous
        Z= new float *[trancheProcZero+1];
        W= new float *[trancheProcZero+1];
        for(int i = 0; i<= trancheProcZero;i++){
            //allocation de mémoire pour les lignes
            Z[i] = new float[ncols];
            W[i] = new float[ncols];
        }
        //mis a jour de dessous & envoi de dernière ligne
        // cout<<"zero tente send"<<endl;
        MPI_Send(donnees[trancheProcZero-1],1,my_line,pid+1,9,MPI_COMM_WORLD);
        //cout<<"zero tente recv"<<endl;
        MPI_Recv(dessous,1,my_line,pid+1,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
        //cout<<"zero passe send/recv"<<endl;

        //IMPORTANT J4AI ENFIN TROUVE LA SYNTAXE DONC POUR LES LIGNES AVEC
        //LES TYPES DERIVES IL FAUT
        //POUR DESSUS ET DESSOUS : &dessous/dessus[0]
        //MAIS POUR ENVOI
        //donnes[case a envoyer] pas de & !!!!!!!

        //nous devons maintenant former les tableaux Z et W
        //creation de Z
        for(int lig = 0 ; lig < trancheProcZero +1; lig++){
            for(int col = 0 ; col< ncols ;col++){
                if( lig == trancheProcZero){
                    //dernière ligne , on ne tape plus dans donnees
                    //mais dans dessous
                    Z[lig][col] = dessous[col];
                }
                else{
                    //cas nominal, on tape dans données
                    Z[lig][col] = donnees[lig][col];
                }
                //cout<<Z[lig][col]<<" ";
            }
            //cout<<endl;
        }
        float max = valRemplissage(Z,ncols,trancheProcZero+1,0.0001);
        for(int l = 0; l<trancheProcZero+1 ;l++){
            for(int c= 0; c<ncols ; c++){
                //nous traitons ici tous les cas d'extrémités
                if(l ==0){ //ligne haute
                    W[l][c] = Z[l][c];
                }
                else{
                    if(l ==trancheProcZero){//ligne basse
                        W[l][c] = Z[l][c];
                    }
                    else{
                        if(c==0){//premiere colonne
                            W[l][c] = Z[l][c];
                        }
                        else{
                            if(c==ncols-1){//derniere colonne
                                W[l][c] = Z[l][c];
                            }
                            else{//milieu
                                W[l][c] = max;
                            }
                        }
                    }
                }
            }
        }
        //cout<<" 0 fini phase 1"<<endl;
    }
    else{
        if(pid == nbprocs-1){
            //on ne dois allouer que pour les données, plus la ligne de
            //dessus
            Z= new float*[tranche+1];
            W=new float*[tranche+1];
            for(int i = 0 ; i<=tranche ;i++){
                //allocation des lignes
                Z[i] = new float[ncols];
                W[i] = new float[ncols];
            }
            //envoi premiere ligne et mise a jour de dessus
            //cout<<"fin tente recv"<<endl;
            MPI_Recv(dessus,1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
            // cout<<"fin tente send"<<endl;
            MPI_Send(donnees[0],1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD);
            // cout<<"ce n'est pas la fin qui bug"<<endl;

            //nous devons maintenant former les tableaux Z et W
            //creation de Z
            for(int lig = 0 ; lig < tranche+1; lig++){
                for(int col = 0 ; col< ncols ;col++){
                    if( lig == 0){
                        //dernière ligne , on ne tape plus dans donnees
                        //mais dans dessous
                        Z[lig][col] = dessus[col];
                    }
                    else{
                        //cas nominal, on tape dans données
                        Z[lig][col] = donnees[lig-1][col];
                    }
                    //	cout<<Z[lig][col]<<" ";
                }
                //cout<<endl;
            }
            float max = valRemplissage(Z,ncols,tranche+1,0.0001);
            for(int l = 0; l<tranche+1 ;l++){
                for(int c= 0; c<ncols ; c++){
                    //nous traitons ici tous les cas d'extrémités
                    if(l ==0){ //ligne haute
                        W[l][c] = Z[l][c];
                    }
                    else{
                        if(l ==tranche){//ligne basse
                            W[l][c] = Z[l][c];
                        }
                        else{
                            if(c==0){//premiere colonne
                                W[l][c] = Z[l][c];
                            }
                            else{
                                if(c==ncols-1){//derniere colonne
                                    W[l][c] = Z[l][c];
                                }
                                else{//milieu
                                    W[l][c] = max;
                                }
                            }
                        }
                    }
                }
            }

        }
        else{//cas nominal
            //cout<<"cas nominal"<<endl;
            //on doit allouer pour les données plus la ligne de dessus
            //et celle de dessous
            Z=new float*[tranche+2];
            W=new float*[tranche+2];
            for(int i=0; i< tranche +2; i++){
                Z[i] = new float[ncols];
                W[i] = new float[ncols];
            }
            //mise a jour de dessus et dessous
            //disjonction habituelle
            if(pid%2 ==0){
                //processus pairs envoi tous et apres recv tout

                //envoi de la fin de son tableau
                MPI_Send(donnees[tranche-1],1,my_line,pid+1,9,MPI_COMM_WORLD);
                //cout<<"send passe proc "<<pid<<endl;
                //Recv du dessous
                MPI_Recv(dessous,1,my_line,pid+1,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);

                //envoi du début
                MPI_Send(donnees[0],1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD);
                //Recv dans dessus
                MPI_Recv(dessus,1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
                //cout<<"c'est pas "<<pid<<" qui chie"<<endl;
            }
            else{
                //processus impairs rec vtout et apres envoi tout
                //Recv dans dessus
                MPI_Recv(dessus,1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
                //cout<<"RECV passe proc "<<pid<<endl;
                //envoi du début


                MPI_Send(donnees[0],1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD);

                //Recv du dessous
                MPI_Recv(dessous,1,my_line,pid+1,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
                //envoi de la fin de son tableau
                MPI_Send(donnees[tranche-1],1,my_line,pid+1,9,MPI_COMM_WORLD);
            }
            // a ce stade tous procesuss normaux ont donnees complet
            // + dessus et dessous
            //nous devons maintenant former les tableaux Z et W
            //creation de Z
            for(int lig = 0 ; lig < tranche+2; lig++){
                for(int col = 0 ; col< ncols ;col++){
                    if( lig == 0){
                        //dernière ligne , on ne tape plus dans donnees
                        //mais dans dessous
                        Z[lig][col] = dessus[col];
                    }
                    else{
                        if(lig == tranche+1){//ligne basse
                            Z[lig][col] = dessous[col];
                        }
                        //cas nominal, on tape dans données
                        else{
                            Z[lig][col] = donnees[lig-1][col];
                        }
                    }
                    // cout<<Z[lig][col]<<" ";
                }
                //cout<<endl;
            }
            float max = valRemplissage(Z,ncols,tranche+2,0.0001);
            for(int l = 0; l<tranche+2 ;l++){
                for(int c= 0; c<ncols ; c++){
                    //nous traitons ici tous les cas d'extrémités
                    if(l ==0){ //ligne haute
                        W[l][c] = Z[l][c];
                    }
                    else{
                        if(l ==tranche+1){//ligne basse
                            W[l][c] = Z[l][c];
                        }
                        else{
                            if(c==0){//premiere colonne
                                W[l][c] = Z[l][c];
                            }
                            else{
                                if(c==ncols-1){//derniere colonne
                                    W[l][c] = Z[l][c];
                                }
                                else{//milieu
                                    W[l][c] = max;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

/**
 * En fonction du numero de processeur, trouver la partie de la matrice des altitudes qui est propre a ce processeur,
 * c'est a dire la partie du MNT qui est exclusivement utilisée par ce processeur
 * @param leMNT : la matrice des altitudes
 * @param trancheProcZero : le nombre de lignes de la tranche du premier processeur
 * @param tranche : le nombre de lignes de la tranche d'un processeur quelconque
 * @param ncols : nombre de colonnes d'une ligne
 * @param pid : le numero du processeur concerné
 */
float ** initDonnees(float ** leMNT, int trancheProcZero,int tranche,int ncols,int pid){
    float ** donnees;
    //cas d'initialisation du proc 0
    if(pid==0){
        // on initialise un tableau avec le nombre de ligne a traiter
        donnees = new float * [trancheProcZero];
        for(int i = 0; i< trancheProcZero; i++){
            // pour chaque ligne, on cree le nombre de cases adequat.
            donnees[i] = new float[ncols];
        }
        //double boucle pour diviser le tableau
        for(int lig = 0; lig < trancheProcZero ; lig ++){
            for(int col = 0; col < ncols; col++){
                //encore une fois , on utilise les coordonnes inverses
                // faire gaffe, mais pas de soucis particulier ici
                donnees[lig][col] = leMNT[lig][col];
            }
        }
    }
    else{
        // les autres
        //on initialise la tables , qui doit recevoir tranche lignes et
        // ncols colonnes
        donnees = new float * [tranche];
        for(int i =0; i< tranche ; i++){
            // on initialise chaque ligne au nombre de cases a recevoir
            donnees[i]= new float[ncols];
        }
        //double boucle pour initialiser les donnees
        for(int lig = 0;lig<tranche;lig++){
            for(int col = 0; col < ncols ; col++){
                // c'est le moment de reflechir aux coordonnees dans le
                // tableau d'origine
                // On doit donc commencer au moins a trancheProcZero
                // car c'est la que fini le proc 0, ensuite , on doit
                // se décaller de (pid-1)*tranche, car chaque processus
                // va lire tranche lignes, mais le proc 1 doit lire a
                // partir de la ligne trancheProcZero, le 2 a
                // trancheProcZero+tranche, etc...

                // Meme astuce pour les coordonnees
                donnees[lig][col] = leMNT[trancheProcZero+(tranche * (pid-1))+lig][col];
            }
        }
        // a cet instant, nous avons bien initialiser les données
    }
    return donnees;
}
/**
 * Enregistrer dans un fichier une matrice d'ecoulements
 * @param s : le nom du fichier a sauvegarder
 * @param W : la matrice des ecoulements a sauvegarder
 */
void saveResPhIII(const char *  s,int ** W,int ncols,int nrows,
                  int xllcorner,int yllcorner,int cellsize,int NODATA_value){
    ofstream outfile;
    cout<<"sauvegarde dans "<<s<<endl;
    outfile.open(s,ios::out);
    outfile<<"ncols "<<ncols<<endl;
    outfile<<"nrows "<<nrows<<endl;
    outfile<<"xllcorner "<<xllcorner<<endl;
    outfile<<"yllcorner "<<yllcorner<<endl;
    outfile<<"cellsize "<<cellsize<<endl;
    outfile<<"NODATA_value "<<NODATA_value<<endl;
    for(int lig = 0; lig < nrows ; lig ++){
        for(int col = 0; col < ncols; col++){
            //encore une fois , on utilise les coordonnes inverses
            // faire gaffe, mais pas de soucis particulier ici
            outfile<<W[lig][col]<<" ";
            //debug += donnees[lig][col] + " ";
        }
        outfile<<endl;
        //debug +="\n";
    }
    outfile.close();
}


/**
 * Enregistrer dans un fichier une matrice d'altitudes
 * @param s : le nom du fichier a sauvegarder
 * @param W : la matrice des altitudes a sauvegarder
 * Une barriere est placée a la fin de cette fonction pour que chacun des processeurs 
 * commence la suite du travail après la fin de l'enregistrement de la matrice
 */
void saveResPhI(const char *  s,float ** W, int pid, int nbprocs, int trancheProcZero,
                int trancheNominal,int tranchefin,int ncols,int nrows,
                int xllcorner,int yllcorner,int cellsize,int NODATA_value){
        //affichage de ce que chacun reçoit
        //cette partie est confirmée comme bonne, la division fonctionne
        // je commente donc tout
         cout<<"sauvegarde dans "<<s<<endl;
        ofstream outfile;
        for(int i = 0 ; i< nbprocs ;i++){
            if(i == pid){
                if(pid==0){
                    outfile.open(s,ios::out);
                    outfile<<"ncols "<<ncols<<endl;
                    outfile<<"nrows "<<nrows<<endl;
                    outfile<<"xllcorner "<<xllcorner<<endl;
                    outfile<<"yllcorner "<<yllcorner<<endl;
                    outfile<<"cellsize "<<cellsize<<endl;
                    outfile<<"NODATA_value "<<NODATA_value<<endl;
                    for(int lig = 0; lig < trancheProcZero ; lig ++){
                        for(int col = 0; col < ncols; col++){
                            //encore une fois , on utilise les coordonnes inverses
                            // faire gaffe, mais pas de soucis particulier ici
                            outfile<<W[lig][col]<<" ";
                            //debug += donnees[lig][col] + " ";
                        }
                        outfile<<endl;
                        //debug +="\n";
                    }
                    outfile.close();
                }
                else{
                    if(pid == nbprocs-1){
                        outfile.open(s,ios::out|ios::app);
                        for(int lig = 1;lig<tranchefin;lig++){
                            for(int col = 0; col < ncols ; col++){
                                // c'est le moment de reflechir aux coordonnees dans le
                                // tableau d'origine
                                // On doit donc commencer au moins a trancheProcZero
                                // car c'est la que fini le proc 0, ensuite , on doit
                                // se décaller de (pid-1)*tranche, car chaque processus
                                // va lire tranche lignes, mais le proc 1 doit lire a
                                // partir de la ligne trancheProcZero, le 2 a
                                // trancheProcZero+tranche, etc...

                                // Meme astuce pour les coordonnees
                                outfile<<W[lig][col]<<" ";
                                //debug += donnees[lig][col] +" ";
                            }
                            outfile<<endl;
                            //debug += "\n";
                        }
                        outfile.close();
                    }else{
                        outfile.open(s,ios::out | ios::app);
                        for(int lig = 1;lig<trancheNominal-1;lig++){
                            for(int col = 0; col < ncols ; col++){
                                // c'est le moment de reflechir aux coordonnees dans le
                                // tableau d'origine
                                // On doit donc commencer au moins a trancheProcZero
                                // car c'est la que fini le proc 0, ensuite , on doit
                                // se décaller de (pid-1)*tranche, car chaque processus
                                // va lire tranche lignes, mais le proc 1 doit lire a
                                // partir de la ligne trancheProcZero, le 2 a
                                // trancheProcZero+tranche, etc...

                                // Meme astuce pour les coordonnees
                                outfile<<W[lig][col]<<" ";
                                //debug += donnees[lig][col] +" ";
                            }
                            outfile<<endl;
                            //debug += "\n";
                        }
                        outfile.close();
                    }
                }
                cout<<pid<<" reached end of save phase I";
            }

            MPI_Barrier(MPI_COMM_WORLD);
        } // fin de l'affichage de la division pour débug
}

/**
 * Enregistrer dans un fichier une matrice d'ecoulements
 * @param s : le nom du fichier a sauvegarder
 * @param W : la matrice des ecoulements a sauvegarder
 */
void savePhaseII(const char * s,int ** W, int pid, int nbprocs, int trancheProcZero,
                 int trancheNominal,int ncols,int nrows,
                 int xllcorner,int yllcorner,int cellsize,int NODATA_value){
    cout<<"sauvegarde dans "<<s<<endl;
    ofstream outfile;
    for(int i = 0 ; i< nbprocs ;i++){
        if(i == pid){
            if(pid==0){
                outfile.open(s,ios::out);
                outfile<<"ncols "<<ncols<<endl;
                outfile<<"nrows "<<nrows<<endl;
                outfile<<"xllcorner "<<xllcorner<<endl;
                outfile<<"yllcorner "<<yllcorner<<endl;
                outfile<<"cellsize "<<cellsize<<endl;
                outfile<<"NODATA_value "<<NODATA_value<<endl;
                for(int lig = 0; lig < trancheProcZero ; lig ++){
                    for(int col = 0; col < ncols; col++){
                        //encore une fois , on utilise les coordonnes inverses
                        // faire gaffe, mais pas de soucis particulier ici
                        outfile<<W[lig][col]<<" ";
                        //debug += donnees[lig][col] + " ";
                    }
                    outfile<<endl;
                    //debug +="\n";
                }
                outfile.close();
            }
            else{
                outfile.open(s,ios::out | ios::app);
                for(int lig = 0;lig<trancheNominal;lig++){
                    for(int col = 0; col < ncols ; col++){
                        // c'est le moment de reflechir aux coordonnees dans le
                        // tableau d'origine
                        // On doit donc commencer au moins a trancheProcZero
                        // car c'est la que fini le proc 0, ensuite , on doit
                        // se décaller de (pid-1)*tranche, car chaque processus
                        // va lire tranche lignes, mais le proc 1 doit lire a
                        // partir de la ligne trancheProcZero, le 2 a
                        // trancheProcZero+tranche, etc...

                        // Meme astuce pour les coordonnees
                        outfile<<W[lig][col]<<" ";
                        //debug += donnees[lig][col] +" ";
                    }
                    outfile<<endl;
                    //debug += "\n";
                }
                outfile.close();
            }
        }
        MPI_Barrier(MPI_COMM_WORLD);
    }
}

/**
 * Allouer un tableau d'ecoulements, en fonction du processeur
 * @param res : la matrice a allouer
 * @param pid : le processeur qui va travailler sur la matrice
 * @param trancheProcZero : la taille du morceau de
 */
void initResPhaseII(int ** &res,int pid,int trancheProcZero,int tranche,int ncols){
    //allouer la baonne taille en fonction dfes cas
    if(pid ==0){
        res= new int * [trancheProcZero];
        for(int i = 0 ; i< trancheProcZero;i++){
            res[i]= new int[ncols];
        }
    }
    else{
        res =new int* [tranche];
        for(int i = 0 ; i< tranche; i++){
            res[i] = new int[ncols];
        }
    }
}

/**
 * Possibilité de factoriser : il y a plusieurs parametres pour le nombre de lignes alors qu'un seul parametre a la fois est utilisé
 * C'est a la fonction appelante de faire l'appel de afficheTab avec le pid et le nombre de lignes adaptés
 * par exemple : matrice W, pid 0, 4 processeurs, 3 lignes pour le processeur 0, 10 colonnes :
 * afficheTabW(W,0,4,3,10); 
 */
void afficheTabW(float ** W, int pid, int nbprocs, int trancheProcZero,int trancheNominal,int tranchefin,int ncols ){
    {
        //affichage de ce que chacun reçoit
        //cette partie est confirmée comme bonne, la division fonctionne
        // je commente donc tout

        for(int i = 0 ; i< nbprocs ;i++){
            if(i == pid){
                cout<<"I'm "<<pid<<endl<<endl;
                if(pid==0){
                    for(int lig = 0; lig < trancheProcZero+1 ; lig ++){
                        for(int col = 0; col < ncols; col++){
                            //encore une fois , on utilise les coordonnes inverses
                            // faire gaffe, mais pas de soucis particulier ici
                            cout<<W[lig][col]<<" ";
                            //debug += donnees[lig][col] + " ";
                        }
                        cout<<endl;
                        //debug +="\n";
                    }
                }
                else{
                    if(pid == nbprocs-1){
                        for(int lig = 0;lig<tranchefin;lig++){
                            for(int col = 0; col < ncols ; col++){
                                // c'est le moment de reflechir aux coordonnees dans le
                                // tableau d'origine
                                // On doit donc commencer au moins a trancheProcZero
                                // car c'est la que fini le proc 0, ensuite , on doit
                                // se décaller de (pid-1)*tranche, car chaque processus
                                // va lire tranche lignes, mais le proc 1 doit lire a
                                // partir de la ligne trancheProcZero, le 2 a
                                // trancheProcZero+tranche, etc...

                                // Meme astuce pour les coordonnees
                                cout<<W[lig][col]<<" ";
                                //debug += donnees[lig][col] +" ";
                            }
                            cout<<endl;
                            //debug += "\n";
                        }
                    }else{
                        for(int lig = 0;lig<trancheNominal;lig++){
                            for(int col = 0; col < ncols ; col++){
                                // c'est le moment de reflechir aux coordonnees dans le
                                // tableau d'origine
                                // On doit donc commencer au moins a trancheProcZero
                                // car c'est la que fini le proc 0, ensuite , on doit
                                // se décaller de (pid-1)*tranche, car chaque processus
                                // va lire tranche lignes, mais le proc 1 doit lire a
                                // partir de la ligne trancheProcZero, le 2 a
                                // trancheProcZero+tranche, etc...

                                // Meme astuce pour les coordonnees
                                cout<<W[lig][col]<<" ";
                                //debug += donnees[lig][col] +" ";
                            }
                            cout<<endl;
                            //debug += "\n";
                        }
                    }
                }
            }
            cout<<endl;
            MPI_Barrier(MPI_COMM_WORLD);
        } // fin de l'affichage de la division pour débug
    }
}

/**
 * Possibilité de factoriser : il y a plusieurs parametres pour le nombre de lignes alors qu'un seul parametre a la fois est utilisé
 */
//comme ça on peut afficher n'importe quel tab 2D
void afficheTab(int ** W, int pid, int nbprocs, int trancheProcZero,int tranche,int ncols ){
    //affichage de ce que chacun reçoit
    //cette partie est confirmée comme bonne, la division fonctionne
    // je commente donc tout
    if (W == NULL){
        cout<<"tab vide"<<endl;
    }
    else{
        for(int i = 0 ; i< nbprocs ;i++){
            if(i == pid){
                cout<<"I'm "<<pid<<endl<<endl;
                if(pid==0){
                    for(int lig = 0; lig < trancheProcZero ; lig ++){
                        for(int col = 0; col < ncols; col++){
                            //encore une fois , on utilise les coordonnes inverses
                            // faire gaffe, mais pas de soucis particulier ici
                            cout<<W[lig][col]<<" ";
                            //debug += donnees[lig][col] + " ";
                        }
                        cout<<endl;
                        //debug +="\n";
                    }
                }
                else{
                    for(int lig = 0;lig<tranche;lig++){
                        for(int col = 0; col < ncols ; col++){
                            // c'est le moment de reflechir aux coordonnees dans le
                            // tableau d'origine
                            // On doit donc commencer au moins a trancheProcZero
                            // car c'est la que fini le proc 0, ensuite , on doit
                            // se décaller de (pid-1)*tranche, car chaque processus
                            // va lire tranche lignes, mais le proc 1 doit lire a
                            // partir de la ligne trancheProcZero, le 2 a
                            // trancheProcZero+tranche, etc...

                            // Meme astuce pour les coordonnees
                            cout<<W[lig][col]<<" ";
                            //debug += donnees[lig][col] +" ";
                        }
                        cout<<endl;
                        //debug += "\n";
                    }
                }
            }
            cout<<endl;
            MPI_Barrier(MPI_COMM_WORLD);
        } // fin de l'affichage de la division pour débug
    }
}

int main(int argc, char ** argv){
   time_t debut_calculs_pid;
    time_t fin_calcul_pid;
    float ** leMNT;
    int trancheProcZero =0;
    int pid;
    int nbprocs;
    int tranche = 0;
    int ncols, nrows, xllcorner, yllcorner, cellsize;
    float NODATA_value;
    MPI_Init(&argc,&argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &pid);
    MPI_Comm_size(MPI_COMM_WORLD, &nbprocs);
    //chargement du fichier en mémoire
   
    float ** donnees = NULL;

    /*
   * Sur les conseils d'Helene Coullon, nous choisirons de
   * découper par ligne car si nous suivons ces conseils
   * l'accès est plus rapide grace au cache(si j'ai
   * bien tout  compris).
   */

    /*
   * Bonne nouvelle j'ai retrouvé mes fichier de chargement
   * de MNT utilisés en OpenGL, ça devrait nous simplifier
   * la tache
   *
   */
    if(pid == 0){
        // le process 0 va s'occuper du chargement
        // gentil processus 0 =D
        ifstream file("test_nodata.txt", ios::in);
        string trash;
        if(file){
            cout<<"fichier test.txt ouvert correctement"<<endl;
            file >> trash;
            file >> ncols;
            file >> trash;
            file >> nrows;
            file >> trash;
            file >> xllcorner;
            file >> trash;
            file >> yllcorner;
            file >> trash;
            file >> cellsize;
            file >> trash;
            file >> NODATA_value;
            leMNT =new float*[nrows]; // nb de ligne et donc taille d'une colonne
            for(int i= 0; i< nrows ; i++){
                leMNT[i] = new float[ncols]; // allocation d'une ligne
            }
            // on passe au remplissage du tableau
            for(int lig=0; lig<nrows ;lig++){
                for(int col= 0; col < ncols ; col++){
                    file >> leMNT[lig][col];
                    //cout<<leMNT[lig][col]<<" ";
                    //attention les coordonnées sont inversées , en effet
                    // de part la création, on est obligé de mettre
                    // l'ordonnée(lig) en premier dans l'allocation
                    // et l'abscisse en second
                    // faire attention pour plus tard
                }
                //cout<<endl;
            }
        }
        else{
            cout<<"impossible d'ouvrir le fichier"<<endl;
        }
    }
    // on doit penser a broadcaster les infos fournis par le fichier, à
    // savoir, le MNT, nrows, ncols, etc...
    MPI_Bcast( &nrows, 1,MPI_INT,0,MPI_COMM_WORLD);
    MPI_Bcast( &ncols, 1,MPI_INT,0,MPI_COMM_WORLD);
    MPI_Bcast( &NODATA_value, 1,MPI_FLOAT,0,MPI_COMM_WORLD);
    
    //les autres processus n'ont pas allouer le mnt
    if(pid !=0){
        leMNT = new float * [nrows];
        for(int i=0; i< ncols ;i++){
            leMNT[i] = new float[ncols];
        }
    }

    //envoi du tout le mnt
    for(int lig=0 ; lig<nrows ; lig++){
        for(int col = 0; col< ncols; col++){

            MPI_Bcast(&leMNT[lig][col],1,MPI_FLOAT,0,MPI_COMM_WORLD);

        }
    }
    //  printf("le méga Bcast est fini\n");

    MPI_Datatype my_line;
    MPI_Type_contiguous(ncols,MPI_FLOAT,&my_line);
    MPI_Type_commit(&my_line);

    //calcul de la taille d'une tranche
    tranche= (nrows / nbprocs);

    //printf("tranche = %d\n",tranche);
    // le proc 0 prend la taille d'une tranche classique, mais traite aussi
    // l'excedent de lignes dans la map
    trancheProcZero = tranche+(nrows % nbprocs);
    // on va peut être maintenant pouvoir passer à l'initialisation de
    // tableaux de données, à savoir , qu'on va avoir pour chaque processus
    // un tableau central, ainsi, q'un ligne du dessus , et une ligne du
    // dessous, sauf pour les extrémités car, dans un MNT, la carte n'est
    // pas torique.
    MPI_Barrier(MPI_COMM_WORLD);

   time(&debut_calculs_pid);
    donnees = initDonnees(leMNT,trancheProcZero,tranche,ncols,pid);
    float ** resteAsauver = new float * [nrows-trancheProcZero];
    for(int i = 0; i<nrows-trancheProcZero; i++){
        resteAsauver[i] = new float[ncols];
    }

    /*if(donnees == NULL){
        cout<<"victoire ça beugue"<<endl;
    }
    else{
        cout<<pid<<" passe initdonnees"<<endl;
    }*/
    //a ce point , chaque process a ses propres datas., nous pouvons donc
    //peut être envisager la phase I en parallele
    float ** Z;
    float ** W;
    float dessus[ncols];
    float dessous[ncols];
    //on dois différencier les cas , proc 0 , dernier proc et cas normal
    MPI_Barrier(MPI_COMM_WORLD);

    //cout<<pid<<" avant phase I"<<endl;
    initTabPhaseI(donnees,Z,W,dessus,dessous,trancheProcZero,tranche,ncols,pid,nbprocs,my_line);
    //cout<<pid<<" passe init phase I"<<endl;


    MPI_Barrier(MPI_COMM_WORLD);
    //il faut maintenant passer a la partie traitement
    //même algorithme que le séquentiel , mais il faut penser a envoyer
    //les bordures a chaque itération
    //toujours disjonction de cas


    /*
      * DEBUT PHASE I
      */
    // on commence le codage de l'algo séquentiel
    int changement = 1;
    bool finish= false;
    int res = 0;
    int * changements_procs = new int[nbprocs];
    for(int i = 0 ; i<nbprocs ;i++){
        changements_procs[i] = 0;
    }
    int trouveOne = 1; //quelqu'un a changé lors de l'iteration,
    //initialisé a vrai pour faire un premier tour de boucle
    //Plus clair que le do {} while car on sait explicitement pourquoi on doit reinitialiser la valeur de trouveOne a chaque tour de boucle :
    //au tour de boucle précédent trouveOne peut valoir 1, il le reinitialiser pour connaitre la valeur pour ce tour de boucle
    //ca mets aussi en evidence que l'implémentation est conforme au pseudo code donné
   while(trouveOne){
        trouveOne=0;
	changement = 0;
        /* on ne traite que le "coeur de la meule"
         * c'est a dire de 1,1 -> nrows-2,ncols-2 (inclues)
         * (cf : REMARQUE).
         */
        //metre au norme de la tailles des processeurs
        /*for(int l = 1; l<nrows-1 ; l++){ // pour chaque cellule c de Z
            for(int c= 1; c< ncols-1 ; c++){ // et w
                if(W[l][c] > Z[l][c]){ // si W(c) > Z(c)
                    //pour chaque n parmis les 8 voisins de c
                    changement = modif8Voisins(W,Z,l,c);
                }
            }
        }*/

        if(pid == 0){//premier proc
            for(int l = 1; l<trancheProcZero ; l++){ // pour chaque cellule c de Z
                for(int c= 1; c< ncols-1 ; c++){ // et w
                    if(W[l][c] > Z[l][c]){ // si W(c) > Z(c)
                        //pour chaque n parmis les 8 voisins de c
                        changement = modif8Voisins(W,Z,l,c,NODATA_value);
                    }
                }
            }
            //mis a jour de dessous & envoi de dernière ligne
            //envoi de la derniere ligne du coeur
            MPI_Send(W[trancheProcZero-1],1,my_line,pid+1,9,MPI_COMM_WORLD);
            MPI_Send(W[trancheProcZero-1],1,my_line,pid+1,9,MPI_COMM_WORLD);
            //reception dans Z de la premiere ligne du +1
            MPI_Recv(Z[trancheProcZero],1,my_line,pid+1,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
            MPI_Recv(W[trancheProcZero],1,my_line,pid+1,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
        }
        else{
            if(pid==nbprocs-1){//dernier proc
                for(int l = 1; l<tranche ; l++){ // pour chaque cellule c de Z
                    for(int c= 1; c< ncols-1 ; c++){ // et w
                        if(W[l][c] > Z[l][c]){ // si W(c) > Z(c)
                            //pour chaque n parmis les 8 voisins de c
                            changement = modif8Voisins(W,Z,l,c,NODATA_value);
                        }
                    }
                }
                //envoi premiere ligne et mise a jour de dessus
                MPI_Recv(Z[0],1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
                MPI_Recv(W[0],1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
                MPI_Send(W[1],1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD);
                MPI_Send(W[1],1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD);
            }
            else{//cas normal
                //traitement idem mais envoi/recv differents
                for(int l = 1; l<tranche+1 ; l++){ // pour chaque cellule c de Z
                    for(int c= 1; c< ncols-1 ; c++){ // et w
                        if(W[l][c] > Z[l][c]){ // si W(c) > Z(c)
                            //pour chaque n parmis les 8 voisins de c
                            changement = modif8Voisins(W,Z,l,c,NODATA_value);
                        }
                    }
                }
                if(pid%2 == 0){//procs pairs
                    //envoi de la fin de son tableau
                    MPI_Send(W[tranche],1,my_line,pid+1,9,MPI_COMM_WORLD);
                    MPI_Send(W[tranche],1,my_line,pid+1,9,MPI_COMM_WORLD);
                    //Recv du dessous
                    MPI_Recv(Z[tranche+1],1,my_line,pid+1,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
                    MPI_Recv(W[tranche+1],1,my_line,pid+1,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
                    //envoi du début
                    MPI_Send(W[1],1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD);
                    MPI_Send(W[1],1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD);
                    //Recv dans dessus
                    MPI_Recv(Z[0],1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
                    MPI_Recv(W[0],1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
                }
                else{ // procs impair
                    MPI_Recv(Z[0],1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
                    MPI_Recv(W[0],1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
                    //envoi du début
                    MPI_Send(W[1],1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD);
                    MPI_Send(W[1],1,my_line,(pid-1+nbprocs)%nbprocs,9,MPI_COMM_WORLD);
                    //Recv du dessous
                    MPI_Recv(Z[tranche+1],1,my_line,pid+1,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
                    MPI_Recv(W[tranche+1],1,my_line,pid+1,9,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
                    //envoi de la fin de son tableau
                    MPI_Send(W[tranche],1,my_line,pid+1,9,MPI_COMM_WORLD);
                    MPI_Send(W[tranche],1,my_line,pid+1,9,MPI_COMM_WORLD);
                }
            }
        }
        //fin des envoi , tant de gather le "changement" pour savoir si les autres ont eu un changement pour cette itération de calcul
        //on a fini si tout le monde a fini ce tour si tout le monde renvoi false
        //cout<<"im "<<pid<<"and res = "<<res<<endl;
        /**
	 * Pour savoir si tout le monde a fini, on récolte les états res de tous les processeurs, que l'on mets dans un tableau avec le gather
	 * Si il existe un entier qui vaut 0 dans le tableau résultat c'est qu'au moins un processeur n'a pas fini de travailler
	 */
        MPI_Gather(&changement,1,MPI_INT,changements_procs,1,MPI_INT,0,MPI_COMM_WORLD);
	/**
	 * Le processeur 0 va s'occuper de la verification
	 */
        if(pid==0){ // traitment du finish case
	    //pour areter tous les procs a la prochaine boucle
            cout<<"pid 0 affiche res"<<endl;
            for(int i = 0; i< nbprocs && !trouveOne; i++){
              //cout<<  
	      if(changements_procs[i] == 1){         
		  /*
                     * une des changement est vrai donc faut continuer
                     * res = 0;
                     */
                    trouveOne =1;
                    cout<<"modifres"<<endl;
                }
                cout<<changements_procs[i]<<" ";
            }
            cout<<endl;
        }
        if(changement){
	  cout<<"before BCAST : im "<<pid<<" and changement = "<<changement<<endl;
	}
	/**
	 * Le processeur 0 connait la valeur de trouveOne et la broadcast a tous les processeurs
	 */
	MPI_Bcast(&trouveOne,1,MPI_INT,0,MPI_COMM_WORLD);
        if(changement){
	  cout<<"after BCAST : im "<<pid<<" and trouveOne = "<<trouveOne<<endl;
	} 
   }
    MPI_Barrier(MPI_COMM_WORLD);
    //  afficheTabW(W,pid,nbprocs,trancheProcZero,tranche+2, tranche+1,ncols);
    //implementer cette fonction pour la sauvegarde du mnt
    saveResPhI("phaseI.txt",W,pid,nbprocs,trancheProcZero,tranche+2,tranche+1,ncols,nrows,xllcorner,yllcorner,cellsize,NODATA_value);
    MPI_Barrier(MPI_COMM_WORLD);
    /*
     * DEBUT DE LA PHASE II
     */
    //appelle de la fonction retourneDirEcoul() sur toutes les cases
    int ** resPhaseII;
    initResPhaseII(resPhaseII,pid,trancheProcZero,tranche,ncols);

    if(pid == 0){//premier proc
        for(int lig = 0 ; lig < trancheProcZero;lig++){
            // on ne va que jusqu'a l'avant derniere ligne, on ne traite que notre partie donnees
            for(int col = 0 ; col < ncols ;col++){
                resPhaseII[lig][col] = retourneDirEcoul(W,trancheProcZero+1,ncols,lig,col,NODATA_value);
            }
        }
    }
    else{
        if(pid==nbprocs-1){//dernier proc
            for(int lig = 1; lig<(tranche+1);lig++){
                //idem avantderniere on ne traite qu eles données
                for(int col = 0 ; col <ncols ; col++){
                    resPhaseII[lig-1][col] = retourneDirEcoul(W,tranche+1,ncols,lig,col,NODATA_value);
                }
            }

        }
        else{//cas normal
            for(int lig = 1; lig<=tranche ; lig++){ // pour chaque cellule c de Z
                for(int col= 0; col< ncols ; col++){ // et w
                    resPhaseII[lig-1][col] = retourneDirEcoul(W,tranche+2,ncols,lig,col,NODATA_value);
                }
            }


        }
    }
    MPI_Barrier(MPI_COMM_WORLD);
    savePhaseII("phaseII.txt",resPhaseII,pid,nbprocs,trancheProcZero,tranche,ncols,nrows,xllcorner,yllcorner,cellsize,NODATA_value);
    MPI_Barrier(MPI_COMM_WORLD);
    //afficheTabW(W,pid,nbprocs,trancheProcZero,tranche+2, tranche+1,ncols);
    // afficheTab(resPhaseII,pid,nbprocs,trancheProcZero,trancheProcZero,ncols);



    /*
     * DEBUT PHASE III
     */

    int ** resPHIII ;
    int **lesDirs;
    int compteurcuvette = 0;

    chargerPhIII(lesDirs,ncols,nrows,xllcorner,yllcorner,cellsize,NODATA_value);
    if(lesDirs == NULL){
        cout<<"chargerPhIII buug"<<endl;
    }
    resPHIII = initResPhIII(ncols,nrows,0);
    //on doit chercher la cuvette dont on doit s'occuper
    //on parcours lesDirs
    for(int lig = 0; lig<nrows;lig++){
        for(int col =0; col<ncols; col++){
            if(lesDirs[lig][col] == ECOULEMENT_INCONNU){
	     if(pid==0){
		resPHIII[lig][col]=ECOULEMENT_INCONNU; 
	      }
	    }
	  if(lesDirs[lig][col] == 0){//c'est une cuvette
                if(compteurcuvette == pid){
                    //c'est ce processus qui doit s'occuper de cette cuvette
                    cout<<pid<<" traite une cuvette"<<endl;
		    int i = trouverAccumulationRec(lesDirs,resPHIII,nrows,ncols,lig,col);
                }
                compteurcuvette = (compteurcuvette+1)%nbprocs;
            }
        }
    }
    
    MPI_Barrier(MPI_COMM_WORLD);
    //afficheTab(resPHIII,pid,nbprocs,nrows,nrows,ncols);

    MPI_Barrier(MPI_COMM_WORLD);
    rassemblerResultat(resPHIII,pid,nbprocs,nrows,ncols);
    MPI_Barrier(MPI_COMM_WORLD);
    time(&fin_calcul_pid);
    cout<<"Fin des calculs pour pid = "<<pid<<" ( "<<fin_calcul_pid-debut_calculs_pid<<" sec au total )"<<endl;
    if(pid == 0){
        saveResPhIII("phaseIII.txt",resPHIII,ncols,nrows,xllcorner,yllcorner,cellsize,NODATA_value);
    }

    MPI_Type_free(&my_line);
    MPI_Finalize();
    return 0;

}


